package com.world.cat.service.sys;

import com.world.cat.app.AppConstant;
import com.world.cat.service.generate.FieldService;
import com.world.common.generate.auto.QField;
import com.world.common.generate.auto.QFieldQueryType;
import com.world.common.model.BaseEntity;
import com.world.common.pojo.Result;
import com.world.common.util.CollectionUtil;
import com.world.common.util.NumberUtil;
import com.world.common.util.SysUtil;
import com.world.core.dao.GenericRepository;
import com.world.core.dao.Restrictions;
import com.world.core.dao.SimpleExpression;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.world.cat.service.generate.FieldService.getNotNullFields;

@Service
@Transactional
public abstract class BaseService<T extends BaseEntity> {
    private static final Logger logger = Logger.getLogger(BaseService.class);

    public abstract GenericRepository getDao();

    public Page findPage(Class clazz, String jsonParams, Pageable pageable) throws Exception {
        List<SimpleExpression> expressionList = BaseService.getExpressionByJsonParams(clazz, jsonParams);
        Page page = getDao().findByPage(expressionList, pageable);
        return page;
    }

    public List getAll(Class clazz, String jsonParams) throws Exception {
        List<SimpleExpression> expressionList = BaseService.getExpressionByJsonParams(clazz, jsonParams);
        List ts = getDao().findAll(expressionList);
        return ts;
    }

    public List getAll() {
        List ts = getDao().findAll();
        return ts;
    }

    public Result save(Class clazz, String jsonParams) throws Exception {
        JSONObject jsonObject = JSONObject.fromObject(jsonParams);
        Result result = BaseService.validateJsonParams(clazz, jsonObject);
        if (!result.isSuccess()) {
            return result;
        }
        T entity = initObjectByJsonParams(clazz, jsonObject);
        T tDb = (T) getDao().save(entity);
        return new Result(true, "成功", tDb);
    }

    public void save(T t) {
        getDao().save(t);
    }

    public T get(String id) {
        return (T) (getDao().findOne(id));
    }

    public void del(String[] ids) {
        List<SimpleExpression> expressionList = new ArrayList<>();
        expressionList.add(Restrictions.in("id", CollectionUtil.arrayToSet(ids), true));
        List os = getDao().findAll(expressionList);
        getDao().delete(os);
    }

    public static List<SimpleExpression> getExpressionByJsonParams(Class clazz, String jsonParams) throws Exception {
        List<SimpleExpression> expressionList = new ArrayList<>();
        if (StringUtils.isNotEmpty(jsonParams)) {
            JSONObject jsonObject = JSONObject.fromObject(jsonParams);
            for (Object o : jsonObject.entrySet()) {
                Map.Entry entry = (Map.Entry) o;
                if (entry.getValue() != null && StringUtils.isNotBlank(entry.getValue().toString())) {
                    String queryField = (String) entry.getKey();
                    if (!queryField.startsWith("_")) {//以下划线开头的参数属于特殊的查询参数，需要手动进行处理
                        if (queryField.endsWith("_start")) {
                            String field = queryField.replace("_start", "");
                            expressionList.add(Restrictions.gte(field, entry.getValue(), true));
                        } else if (queryField.endsWith("_end")) {
                            String field = queryField.replace("_end", "");
                            expressionList.add(Restrictions.lte(field, entry.getValue(), true));
                        } else {
                            if (StringUtils.isNotEmpty(queryField)) {
                                if (AppConstant.baseEntityFields.contains(queryField)) {
                                    expressionList.add(Restrictions.eq(queryField, entry.getValue(), true));
                                } else {
                                    Field field = clazz.getDeclaredField(queryField);
                                    QField qField = field.getAnnotation(QField.class);
                                    if (QFieldQueryType.eq.equals(qField.queryType())) {
                                        expressionList.add(Restrictions.eq(queryField, entry.getValue(), true));
                                    } else if (QFieldQueryType.like.equals(qField.queryType())) {
                                        expressionList.add(Restrictions.like(queryField, (String) entry.getValue(), true));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        return expressionList;
    }

    public T initObjectByJsonParams(Class clazz, JSONObject jsonObject) throws Exception {
        T entity = null;
        String id = (String) jsonObject.get("id");
        if (StringUtils.isEmpty(id)) {
            entity = (T) clazz.newInstance();
        } else {
            entity = (T) getDao().findOne(id);
        }
        for (Object o : jsonObject.entrySet()) {
            Map.Entry entry = (Map.Entry) o;
            String pageFiled = (String) entry.getKey();
            if (!"id".equals(pageFiled)) {
                Field field = clazz.getDeclaredField(pageFiled);
                Method method = clazz.getDeclaredMethod("set" + StringUtils.capitalize(pageFiled), field.getType());

                String value = (String) entry.getValue();
                if (String.class.equals(field.getType())) {
                    method.invoke(entity, value);
                } else if (Integer.class.equals(field.getType())) {
                    method.invoke(entity, NumberUtil.intValue(value));
                } else if (Long.class.equals(field.getType())) {
                    method.invoke(entity, NumberUtil.longValue(value));
                } else if (Double.class.equals(field.getType())) {
                    method.invoke(entity, NumberUtil.doubleValue(value));
                } else if (field.getType().isEnum()) {
                    Class enumclass = field.getType();
                    if (StringUtils.isNotEmpty(value)) {
                        method.invoke(entity, Enum.valueOf(enumclass, value));
                    }
                } else if (Date.class.equals(field.getType())) {
                    QField qField = field.getAnnotation(QField.class);
                    SimpleDateFormat format = new SimpleDateFormat(qField.format());
                    if (StringUtils.isNotEmpty(value)) {
                        method.invoke(entity, format.parse(value));
                    }
                }
            }
        }

        return entity;
    }

    public static Result validateJsonParams(Class clazz, JSONObject jsonObject) {
        List<String> notNulls = getNotNullFields(clazz);
        for (Object o : jsonObject.entrySet()) {
            Map.Entry entry = (Map.Entry) o;
            if (notNulls.contains(entry.getKey().toString())) {
                if (SysUtil.isEmpty(entry.getValue().toString())) {
                    return new Result(false, "必填参数为空");
                }
                notNulls.remove(entry.getKey().toString());
            }
        }
        if (CollectionUtil.isNotEmpty(notNulls)) {
            for (String notNull : notNulls) {
                logger.error("字段不能为空：" + notNull);
            }
            return new Result(false, "必填参数页面未传递值");
        }

        return new Result(true, "成功");
    }

    public static Result validateJsonEditParams(Class clazz, JSONObject jsonObject) {
        List<String> notNulls = FieldService.getNotNullEditFields(clazz);
        for (Object o : jsonObject.entrySet()) {
            Map.Entry entry = (Map.Entry) o;
            if (notNulls.contains(entry.getKey().toString())) {
                if (SysUtil.isEmpty(entry.getValue().toString())) {
                    return new Result(false, "必填参数为空");
                }
                notNulls.remove(entry.getKey().toString());
            }
        }
        if (CollectionUtil.isNotEmpty(notNulls)) {
            for (String notNull : notNulls) {
                logger.error("字段不能为空：" + notNull);
            }
            return new Result(false, "必填参数页面未传递值");
        }

        return new Result(true, "成功");
    }
}
